﻿using System.ComponentModel;
using System.Linq.Expressions;

namespace BPM.Web.Shared.Data;

/// <summary>
/// 业务基类
/// </summary>
[DisplayName("业务基类")]
public class BaseVM : INotifyPropertyChanged
{
    /// <summary>
    /// 属性变化事件
    /// </summary>
    public event PropertyChangedEventHandler? PropertyChanged;

    /// <summary>
    /// 字段内容清除重置
    /// </summary>
    public virtual void Clear()
    {

    }

    /// <summary>
    /// 通知状态已经改变
    /// </summary>
    public virtual void Changed()
        => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(PropertyChanged)));

    /// <summary>
    /// 通知状态已经改变
    /// </summary>
    /// <typeparam name="TValue"></typeparam>
    /// <param name="expression"></param>
    public virtual void Changed<TValue>(Expression<Func<TValue>> expression)
        => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(ParseAccessor(expression)));

    /// <summary>
    /// 通知状态已经改变
    /// </summary>
    public virtual Task ChangedAsync()
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(PropertyChanged)));
        return Task.CompletedTask;
    }

    /// <summary>
    /// 通知状态已经改变
    /// </summary>
    public virtual Task ChangedAsync<TValue>(Expression<Func<TValue>> expression)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(ParseAccessor(expression)));
        return Task.CompletedTask;
    }

    private static string ParseAccessor<T>(Expression<Func<T>> accessor)
    {
        if (accessor.Body == null)
        {
            throw new ArgumentNullException(nameof(accessor));
        }

        var expression = accessor.Body;
        if (expression is UnaryExpression unaryExpression && unaryExpression.NodeType == ExpressionType.Convert && unaryExpression.Type == typeof(object))
        {
            expression = unaryExpression.Operand;
        }

        if (expression is not MemberExpression memberExpression)
        {
            throw new ArgumentException("Cannot accessors (fields, properties) of an object.");
        }

        return memberExpression.Member.Name;
    }
}
